package com.ilearn.iodata.iolingo.service.processor;

import com.ilearn.iodata.iolingo.service.GetPrimitiveService;
import lombok.extern.slf4j.Slf4j;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmKeyPropertyRef;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.*;
import org.apache.olingo.server.api.deserializer.DeserializerException;
import org.apache.olingo.server.api.processor.PrimitiveProcessor;
import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.serializer.SerializerResult;
import org.apache.olingo.server.api.uri.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.List;
import java.util.Locale;

/**
 * 其实带括号的方式，具备$select方式，就可以解决问题了，基本上可以不用这个接口。
 */
@Slf4j
@Service
public class GenericPrimitiveProcessor implements PrimitiveProcessor {

    private OData odata;
    private ServiceMetadata serviceMetadata;

    @Autowired
    private GetPrimitiveService getPrimitiveService;


    @Override
    public void init(OData odata, ServiceMetadata serviceMetadata) {
        this.odata = odata;
        this.serviceMetadata = serviceMetadata;
    }

    /**
     * 应该是先传表名(id=1)/字段名的结构：  EntitySetName(id=1)/name
     * @param request
     * @param response
     * @param uriInfo
     * @param responseFormat
     * @throws ODataApplicationException
     * @throws ODataLibraryException
     */
    @Override
    public void readPrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {
        // 1. Retrieve info from URI
        // 1.1. retrieve the info about the requested entity set
        List<UriResource> resourceParts = uriInfo.getUriResourceParts();

        final UriResource lastItem = resourceParts.get(resourceParts.size() - 1);

        UriResourceKind kind = lastItem.getKind();

        // Note: only in our example we can rely that the first segment is the EntitySet
        UriResourceEntitySet uriEntityset = (UriResourceEntitySet) resourceParts.get(0);
        EdmEntitySet edmEntitySet = uriEntityset.getEntitySet();
        // the key for the entity 请求发送过来的参数键值对
        List<UriParameter> keyPredicates = uriEntityset.getKeyPredicates();

        // 1.2. retrieve the requested (Edm) property
        UriResourceProperty uriProperty = (UriResourceProperty)resourceParts.get(resourceParts.size() -1); // the last segment is the Property
        EdmProperty edmProperty = uriProperty.getProperty();
        String edmPropertyName = edmProperty.getName();
        // in our example, we know we have only primitive types in our model
        EdmPrimitiveType edmPropertyType = (EdmPrimitiveType) edmProperty.getType();

        // 2. retrieve data from backend
        Property property = getPrimitiveByKey(edmEntitySet, keyPredicates, edmProperty);


        // 3. serialize
        Object value = property.getValue();
        if (value != null) {
            // 3.1. configure the serializer
            ODataSerializer serializer = odata.createSerializer(responseFormat);
            ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).navOrPropertyPath(edmPropertyName).build();
            PrimitiveSerializerOptions options = PrimitiveSerializerOptions.with().contextURL(contextUrl).build();
            // 3.2. serialize
            SerializerResult serializerResult = serializer.primitive(serviceMetadata, edmPropertyType, property, options);
            InputStream propertyStream = serializerResult.getContent();

            //4. configure the response object
            response.setContent(propertyStream);
            response.setStatusCode(HttpStatusCode.OK.getStatusCode());
            response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
        } else {
            // in case there's no value for the property, we can skip the serialization
            response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
        }
    }

    @Override
    public void updatePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat, ContentType responseFormat)
            throws ODataApplicationException, DeserializerException, SerializerException {
        throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
    }

    @Override
    public void deletePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo)
            throws ODataApplicationException, ODataLibraryException {
        throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
    }


    private Property getPrimitiveByKey(EdmEntitySet edmEntitySet, List<UriParameter> keyPredicates, EdmProperty edmProperty) {

        // 用于传输到后面生成URI的createId使用
        List<EdmKeyPropertyRef> keyPropertyRefs = edmEntitySet.getEntityType().getKeyPropertyRefs();


        String entitySetName = edmEntitySet.getName();

        StringBuilder sql = new StringBuilder();
        sql.append("select ");
        sql.append(edmProperty.getName());
        sql.append(" from ");
        sql.append(entitySetName);
        sql.append(" where 1=1");

        for (UriParameter keyPredicate : keyPredicates) {

            //EdmKeyPropertyRef keyPropertyRef = edmEntitySet.getEntityType().getKeyPropertyRef(keyPredicate.getName());

            /*String value = keyPredicate.getText();
            if (keyPropertyRef.getProperty().getType().getKind().equals(EdmTypeKind.PRIMITIVE)) {
                if (keyPropertyRef.getProperty().getType().getFullQualifiedName().equals(EdmPrimitiveTypeKind.String.getFullQualifiedName())) {
                    value = OlingoUtil.mkString(value, "'");
                }
            }*/
            //keyPropertyRef.getProperty().getType().getKind();
            sql.append(" and " + keyPredicate.getName() + "=" + keyPredicate.getText()); // + keyPredicate.getText()
        }
        String sqlStatement = sql.toString();
        System.out.println("》》》》》》》》》 " + sqlStatement + " 《《《《《《《《《《《《《《《");
        Property primitive = getPrimitiveService.getPrimitiveByJdbcTemplate(sqlStatement, entitySetName, keyPropertyRefs);
        return primitive;
    }

}
